import WebSocket from 'ws';
import { createModuleLogger } from '@/utils/logger';
import { PriceService } from '@/services/price/PriceService';
import { MonitoredTokenService } from '@/services/token/MonitoredTokenService';

const logger = createModuleLogger('websocket-price-service');

interface PriceUpdate {
  symbol: string;
  price: number;
  timestamp: number;
  source: string;
}

interface ProviderConfig {
  name: string;
  url: string;
  active: boolean;
  reconnectDelay: number;
}

export class WebSocketPriceService {
  private static instance: WebSocketPriceService;
  private priceService: PriceService;
  private monitoredTokenService: MonitoredTokenService;
  private connections = new Map<string, WebSocket>();
  private prices = new Map<string, PriceUpdate>();
  private subscribers = new Set<(update: PriceUpdate) => void>();
  private reconnectTimers = new Map<string, NodeJS.Timeout>();
  
  // 多个WebSocket价格数据提供商
  private providers: ProviderConfig[] = [
    {
      name: 'binance',
      url: 'wss://stream.binance.com:9443/ws/!ticker@arr',
      active: false, // 暂时禁用，连接有问题
      reconnectDelay: 10000
    },
    {
      name: 'coinbase',
      url: 'wss://ws-feed.exchange.coinbase.com',
      active: true,
      reconnectDelay: 5000
    },
    {
      name: 'kraken',
      url: 'wss://ws.kraken.com',
      active: true,
      reconnectDelay: 5000
    }
  ];

  private constructor() {
    this.priceService = PriceService.getInstance();
    this.monitoredTokenService = MonitoredTokenService.getInstance();
  }

  public static getInstance(): WebSocketPriceService {
    if (!WebSocketPriceService.instance) {
      WebSocketPriceService.instance = new WebSocketPriceService();
    }
    return WebSocketPriceService.instance;
  }

  // 启动WebSocket价格流
  public async start(): Promise<void> {
    logger.info('🚀 启动WebSocket价格服务...');
    
    // 等待PriceService初始化完成，获取白名单
    await this.waitForWhitelist();
    
    // 启动所有活跃的提供商
    for (const provider of this.providers) {
      if (provider.active) {
        this.connectProvider(provider);
      }
    }
    
    logger.info('✅ WebSocket价格服务已启动');
  }

  // 等待白名单准备完成
  private async waitForWhitelist(): Promise<void> {
    try {
      // 从数据库获取监控代币数量
      const stats = await this.monitoredTokenService.getStats();
      
      // 如果数据库中有足够的代币，直接使用
      if (stats.activeTokens > 10) {
        logger.info(`📊 数据库中有 ${stats.activeTokens} 个活跃监控代币，开始WebSocket连接`);
        return;
      }
      
      // 如果数据库中代币太少，等待一小段时间或使用fallback
      logger.warn(`📊 数据库中只有 ${stats.activeTokens} 个活跃代币，建议先运行初始化脚本`);
      
      // 检查fallback白名单
      const fallbackStats = this.priceService.getWhitelistStats();
      if (fallbackStats.totalSupported > 50) {
        logger.info(`📊 使用fallback白名单，支持 ${fallbackStats.totalSupported} 个代币`);
        return;
      }
      
      logger.warn(`📊 警告：代币列表不足，继续运行但可能监控效果有限`);
      
    } catch (error) {
      logger.error('获取代币列表失败，使用fallback白名单:', error);
    }
  }

  // 连接到特定提供商
  private connectProvider(provider: ProviderConfig): void {
    try {
      // 减少连接日志 - 只在首次连接时记录
      const isFirstConnection = !this.connections.has(provider.name);
      if (isFirstConnection) {
        logger.info(`🔗 初始连接到 ${provider.name}`);
      }
      
      const ws = new WebSocket(provider.url);
      this.connections.set(provider.name, ws);

      ws.on('open', () => {
        if (isFirstConnection) {
          logger.info(`✅ ${provider.name} WebSocket 连接成功`);
        }
        this.setupProviderSubscription(provider.name, ws);
      });

      ws.on('message', (data: WebSocket.Data) => {
        this.handleMessage(provider.name, data);
      });

      ws.on('error', (error) => {
        // 只记录非常见错误，减少日志噪音
        if (error.message && !error.message.includes('ECONNRESET') && !error.message.includes('timeout')) {
          logger.debug(`${provider.name} WebSocket 错误:`, error.message);
        }
      });

      ws.on('close', (code, reason) => {
        // 只记录异常关闭，正常关闭不输出日志
        if (code !== 1000) {
          logger.debug(`${provider.name} WebSocket 关闭: ${code}`);
        }
        this.connections.delete(provider.name);
        this.scheduleReconnect(provider);
      });

    } catch (error) {
      logger.error(`${provider.name} 连接失败:`, error);
      this.scheduleReconnect(provider);
    }
  }

  // 设置提供商订阅
  private setupProviderSubscription(providerName: string, ws: WebSocket): void {
    switch (providerName) {
      case 'binance':
        // Binance 的 ticker stream 自动推送所有交易对
        logger.info(`📡 Binance: 已订阅全市场ticker流`);
        break;
        
      case 'coinbase':
        this.subscribeCoinbase(ws);
        break;
        
      case 'kraken':
        this.subscribeKraken(ws);
        break;
    }
  }

  // Coinbase Pro WebSocket 订阅
  private subscribeCoinbase(ws: WebSocket): void {
    const subscribe = {
      type: 'subscribe',
      product_ids: this.getTopTradingPairs('coinbase'),
      channels: ['ticker']
    };
    
    ws.send(JSON.stringify(subscribe));
    logger.debug(`📡 Coinbase: 已订阅 ${subscribe.product_ids.length} 个交易对`);
  }

  // Kraken WebSocket 订阅
  private subscribeKraken(ws: WebSocket): void {
    const subscribe = {
      event: 'subscribe',
      pair: this.getTopTradingPairs('kraken'),
      subscription: { name: 'ticker' }
    };
    
    ws.send(JSON.stringify(subscribe));
    logger.info(`📡 Kraken: 已订阅 ${subscribe.pair.length} 个交易对`);
  }

  // 获取主要交易对（根据白名单）
  private getTopTradingPairs(exchange: string): string[] {
    const stats = this.priceService.getWhitelistStats();
    const supportedTokens = ['BTC', 'ETH', 'BNB', 'ADA', 'SOL', 'MATIC', 'LINK', 'UNI', 'DOGE', 'LTC'];
    
    switch (exchange) {
      case 'coinbase':
        return supportedTokens.slice(0, 50).map(token => `${token}-USD`);
      case 'kraken':
        return supportedTokens.slice(0, 50).map(token => `${token}USD`);
      default:
        return [];
    }
  }

  // 处理消息
  private handleMessage(providerName: string, data: WebSocket.Data): void {
    try {
      const message = JSON.parse(data.toString());
      
      switch (providerName) {
        case 'binance':
          this.handleBinanceMessage(message);
          break;
        case 'coinbase':
          this.handleCoinbaseMessage(message);
          break;
        case 'kraken':
          this.handleKrakenMessage(message);
          break;
      }
    } catch (error) {
      // 静默处理解析错误
    }
  }

  // 处理Binance消息
  private handleBinanceMessage(message: any): void {
    if (Array.isArray(message)) {
      // 处理ticker数组
      message.forEach(ticker => {
        if (ticker.s && ticker.c) {
          const symbol = this.extractSymbol(ticker.s, 'binance');
          if (symbol && this.priceService.isTokenSupported(symbol)) {
            this.updatePrice({
              symbol: symbol,
              price: parseFloat(ticker.c),
              timestamp: Date.now(),
              source: 'binance'
            });
          }
        }
      });
    }
  }

  // 处理Coinbase消息
  private handleCoinbaseMessage(message: any): void {
    if (message.type === 'ticker' && message.product_id && message.price) {
      const symbol = this.extractSymbol(message.product_id, 'coinbase');
      if (symbol && this.priceService.isTokenSupported(symbol)) {
        this.updatePrice({
          symbol: symbol,
          price: parseFloat(message.price),
          timestamp: Date.now(),
          source: 'coinbase'
        });
      }
    }
  }

  // 处理Kraken消息
  private handleKrakenMessage(message: any): void {
    if (Array.isArray(message) && message.length >= 4) {
      const [channelId, data, channelName, pair] = message;
      if (channelName === 'ticker' && data.c) {
        const symbol = this.extractSymbol(pair, 'kraken');
        if (symbol && this.priceService.isTokenSupported(symbol)) {
          this.updatePrice({
            symbol: symbol,
            price: parseFloat(data.c[0]),
            timestamp: Date.now(),
            source: 'kraken'
          });
        }
      }
    }
  }

  // 从交易对名称提取代币符号
  private extractSymbol(pair: string, exchange: string): string | null {
    try {
      switch (exchange) {
        case 'binance':
          // BTCUSDT -> BTC
          if (pair.endsWith('USDT')) {
            return pair.slice(0, -4);
          } else if (pair.endsWith('BUSD')) {
            return pair.slice(0, -4);
          }
          return null;
          
        case 'coinbase':
          // BTC-USD -> BTC
          return pair.split('-')[0];
          
        case 'kraken':
          // BTCUSD -> BTC
          if (pair.endsWith('USD')) {
            return pair.slice(0, -3);
          }
          return null;
          
        default:
          return null;
      }
    } catch {
      return null;
    }
  }

  // 更新价格
  private updatePrice(update: PriceUpdate): void {
    const current = this.prices.get(update.symbol);
    
    // 只有价格变化才更新
    if (!current || Math.abs(current.price - update.price) / current.price > 0.001) {
      this.prices.set(update.symbol, update);
      
      // 注意：PriceService已简化，不再需要同步缓存
      
      // 通知订阅者
      this.notifySubscribers(update);
      
      logger.debug(`💰 ${update.symbol}: $${update.price.toFixed(4)} (${update.source})`);
    }
  }

  // 通知订阅者
  private notifySubscribers(update: PriceUpdate): void {
    this.subscribers.forEach(callback => {
      try {
        callback(update);
      } catch (error) {
        logger.error('价格更新回调失败:', error);
      }
    });
  }

  // 安排重连
  private scheduleReconnect(provider: ProviderConfig): void {
    const existingTimer = this.reconnectTimers.get(provider.name);
    if (existingTimer) {
      clearTimeout(existingTimer);
    }

    const timer = setTimeout(() => {
      // 减少重连日志，只在debug模式下显示
      logger.debug(`重连 ${provider.name}...`);
      this.connectProvider(provider);
      this.reconnectTimers.delete(provider.name);
    }, provider.reconnectDelay);

    this.reconnectTimers.set(provider.name, timer);
  }

  // 订阅价格更新
  public subscribe(callback: (update: PriceUpdate) => void): void {
    this.subscribers.add(callback);
  }

  // 取消订阅
  public unsubscribe(callback: (update: PriceUpdate) => void): void {
    this.subscribers.delete(callback);
  }

  // 获取当前价格
  public getPrice(symbol: string): number | null {
    const upperSymbol = symbol.toUpperCase();
    
    // 稳定币价格映射
    const stablecoins = ['USDT', 'USDC', 'DAI', 'BUSD', 'TUSD', 'FRAX', 'LUSD'];
    if (stablecoins.includes(upperSymbol)) {
      return 1.0;
    }

    // 包装代币映射
    const wrappedTokenMappings: Record<string, string> = {
      'WETH': 'ETH',
      'WBTC': 'BTC',
      'WBNB': 'BNB',
      'WMATIC': 'MATIC', 
      'WAVAX': 'AVAX',
      'WFTM': 'FTM'
    };

    const baseSymbol = wrappedTokenMappings[upperSymbol] || upperSymbol;
    const update = this.prices.get(baseSymbol);
    return update ? update.price : null;
  }

  // 获取所有价格
  public getAllPrices(): Map<string, PriceUpdate> {
    return new Map(this.prices);
  }

  // 获取连接状态
  public getConnectionStatus(): Record<string, boolean> {
    const status: Record<string, boolean> = {};
    for (const provider of this.providers) {
      const ws = this.connections.get(provider.name);
      status[provider.name] = ws ? ws.readyState === WebSocket.OPEN : false;
    }
    return status;
  }

  // 等待价格预热完成
  public async waitForPriceWarmup(timeoutMs: number = 30000): Promise<boolean> {
    logger.info('🔥 等待WebSocket价格预热...');
    
    const startTime = Date.now();
    // 主链代币优先级最高 - 这些是各个区块链的原生代币
    const primaryChainTokens = ['ETH', 'BTC', 'BNB', 'SOL']; 
    // 重要的稳定币和常用代币
    const secondaryTokens = ['USDT', 'USDC', 'WETH', 'WBTC'];
    
    while (Date.now() - startTime < timeoutMs) {
      // 检查连接状态
      const connections = this.getConnectionStatus();
      const hasActiveConnection = Object.values(connections).some(connected => connected);
      
      if (!hasActiveConnection) {
        logger.debug('⏳ 等待WebSocket连接建立...');
        await new Promise(resolve => setTimeout(resolve, 1000));
        continue;
      }
      
      // 检查主链代币价格
      const availablePrimaryPrices = primaryChainTokens.filter(token => {
        const price = this.getPrice(token);
        return price !== null && price > 0;
      });
      
      // 检查次要代币价格
      const availableSecondaryPrices = secondaryTokens.filter(token => {
        const price = this.getPrice(token);
        return price !== null && price > 0;
      });
      
      logger.debug(`📊 主链代币价格: ${availablePrimaryPrices.join(', ')} (${availablePrimaryPrices.length}/${primaryChainTokens.length})`);
      logger.debug(`📊 次要代币价格: ${availableSecondaryPrices.join(', ')} (${availableSecondaryPrices.length}/${secondaryTokens.length})`);
      
      // 预热成功条件：获取到至少75%的主链代币价格
      const primarySuccessRate = availablePrimaryPrices.length / primaryChainTokens.length;
      if (primarySuccessRate >= 0.75) {
        logger.info(`✅ 价格预热完成！主链代币: ${availablePrimaryPrices.length}/${primaryChainTokens.length}, 次要代币: ${availableSecondaryPrices.length}/${secondaryTokens.length}`);
        
        // 异步获取数据库中的其他监控代币价格（不阻塞启动）
        this.warmupMonitoredTokensAsync();
        
        return true;
      }
      
      // 继续等待
      await new Promise(resolve => setTimeout(resolve, 2000));
    }
    
    // 获取最终的主链代币价格状态
    const finalPrimaryPrices = primaryChainTokens.filter(token => {
      const price = this.getPrice(token);
      return price !== null && price > 0;
    });
    
    logger.warn(`⚠️ 价格预热超时 (${timeoutMs}ms)，当前主链代币价格覆盖率: ${Math.round((finalPrimaryPrices.length / primaryChainTokens.length) * 100)}%`);
    
    // 即使超时，也异步获取监控代币价格
    this.warmupMonitoredTokensAsync();
    
    return false;
  }

  // 异步预热监控代币价格（不阻塞启动流程）
  private async warmupMonitoredTokensAsync(): Promise<void> {
    try {
      logger.info('🔄 后台获取监控代币价格...');
      
      const activeTokens = await this.monitoredTokenService.getActiveTokenSymbols();
      const batchSize = 10; // 每批处理10个代币
      let processedCount = 0;
      
      // 分批处理，避免一次性请求过多
      for (let i = 0; i < activeTokens.length; i += batchSize) {
        const batch = activeTokens.slice(i, i + batchSize);
        
        // 检查这批代币的价格（使用映射后的价格检查）
        const batchPrices = batch.filter(symbol => {
          const price = this.getPrice(symbol); // 这个方法已经处理了映射
          return price !== null && price > 0;
        });
        
        processedCount += batchPrices.length;
        
        if (batchPrices.length > 0) {
          logger.debug(`📊 批次 ${Math.floor(i/batchSize) + 1}: 获取到 ${batchPrices.length}/${batch.length} 个代币价格 [${batchPrices.join(', ')}]`);
        }
        
        // 避免过于频繁的处理
        if (i + batchSize < activeTokens.length) {
          await new Promise(resolve => setTimeout(resolve, 1000));
        }
      }
      
      logger.info(`📊 监控代币价格预热完成: ${processedCount}/${activeTokens.length} 个代币已获取价格`);
      
    } catch (error) {
      logger.warn('监控代币价格预热失败:', error);
    }
  }

  // 获取监控代币的实时价格
  public async getMonitoredTokenPrices(): Promise<Map<string, number>> {
    const prices = new Map<string, number>();
    
    try {
      // 获取数据库中的活跃监控代币
      const activeTokens = await this.monitoredTokenService.getActiveTokenSymbols();
      
      for (const symbol of activeTokens) {
        const price = this.getPrice(symbol);
        if (price !== null && price > 0) {
          prices.set(symbol, price);
        }
      }
      
      logger.info(`📊 获取到 ${prices.size} 个监控代币的实时价格`);
      return prices;
      
    } catch (error) {
      logger.error('获取监控代币价格失败:', error);
      return prices;
    }
  }

  // 停止服务
  public stop(): void {
    logger.info('🛑 停止WebSocket价格服务...');
    
    // 关闭所有连接
    this.connections.forEach((ws, name) => {
      logger.info(`🔌 关闭 ${name} 连接`);
      ws.close();
    });
    
    // 清理定时器
    this.reconnectTimers.forEach(timer => clearTimeout(timer));
    
    this.connections.clear();
    this.reconnectTimers.clear();
    this.subscribers.clear();
    
    logger.info('✅ WebSocket价格服务已停止');
  }
} 